package com.example.log.alarm.advice.thread.pool;

import net.bytebuddy.asm.Advice;

import java.lang.reflect.Field;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @program: spring-agent
 * @description:
 * @author: zt22328 赵儒定
 * @create: 2023-05-05 09:38
 **/
public class ThreadPoolAdviceInterceptor {

    /**
     * ThreadPoolExecutor
     * final void reject(Runnable command)
     * @param args
     */
    @Advice.OnMethodEnter
    public static void enter(@Advice.This(optional = true) Object object,
                             @Advice.AllArguments Object[] args) {
        if (args == null || !(args[0] instanceof Runnable)) {
            return;
        }
        try {
            Class<?> aClass = Class.forName("com.example.log.alarm.spy.BootstrapQueuedSpy_internal");
            Field field = aClass.getDeclaredField("threadPoolRejectQueue");
            field.setAccessible(true);
            BlockingQueue<Map<String, Object>> threadPoolRejectQueue = (BlockingQueue<Map<String, Object>>) field.get(null);
            Map<String, Object> map = new HashMap<>();
            map.put("threadPool", object);
            map.put("threadName", Thread.currentThread().getName());
            map.put("stackTrace", new Exception("Stack trace"));
            threadPoolRejectQueue.offer(map);
        } catch (Exception e) {

        }
    }

    /**
     * 方法拦截
     * new Throwable();
     * @param object
     */
    @Advice.OnMethodExit
    public static void exit(@Advice.This Object object,
                            @Advice.AllArguments Object[] args) {
        if (args == null || !(object instanceof ThreadPoolExecutor)) {
            return;
        }
        try {
            Class<?> aClass = Class.forName("com.example.log.alarm.spy.BootstrapQueuedSpy_internal");
            Field field = aClass.getDeclaredField("threadPoolQueue");
            field.setAccessible(true);
            BlockingQueue<Map<String, Object>> queue = (BlockingQueue<Map<String, Object>>) field.get(null);
            Map<String, Object> map = new HashMap<>();
            map.put("threadPool", object);
            map.put("threadName", Thread.currentThread().getName());
            map.put("createdAt", LocalDateTime.now());
            map.put("stackTrace", new Exception("Stack trace"));
            queue.offer(map);
        } catch (Exception e) {

        }
    }

}
